package com.njlime.core.base.repository.impl;

import com.alibaba.fastjson.JSON;
import com.njlime.core.base.repository.BaseDao;
import com.njlime.core.utils.StringUtil;
import com.njlime.sys.entities.Role;
import com.njlime.sys.entities.Unit;
import com.njlime.sys.entities.User;
import com.njlime.sys.security.util.UserUtils;
import org.apache.log4j.Logger;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class BaseDaoImpl<T> implements BaseDao<T> {

    Logger logger = Logger.getLogger(BaseDaoImpl.class);

    @PersistenceContext
    protected EntityManager em;

    private Class<T> clazz;

    public BaseDaoImpl() {
        ParameterizedType pType = (ParameterizedType) this.getClass().getGenericSuperclass();// 获取当前new的对象的泛型父类
        this.clazz = (Class<T>) pType.getActualTypeArguments()[0];// 获取类型参数的真是值，就是泛型参数的个数；
    }

    @Override
    public List<T> findList(String sql, List<Object> args) {
        List<T> list = new ArrayList<T>();
        try {
            Query query = em.createNativeQuery(sql, clazz);
            if (args != null && args.size() > 0) {
                for (int i = 0; i < args.size(); i++) {
                    query.setParameter(i + 1, args.get(i));
                }
            }
            logger.info("sql:" + sql + " " + JSON.toJSONString(args));
            list = (List<T>) query.getResultList();
        } catch (NoResultException ne){
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("EntityManager执行sql出错：" + e.getMessage());
        }
        return list;
    }

    @Override
    public T findOne(String sql, List<Object> args) {
        T t = null;
        try {
            Query query = em.createNativeQuery(sql, clazz);
            if (args != null && args.size() > 0) {
                for (int i = 0; i < args.size(); i++) {
                    query.setParameter(i + 1, args.get(i));
                }
            }
            logger.info("sql:" + sql + " " + JSON.toJSONString(args));
            t = (T) query.getSingleResult();
        } catch (NoResultException ne){
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("EntityManager执行sql出错：" + e.getMessage());
        }
        return t;
    }

    @Override
    public Object findCount(String sql, List<Object> args) {
        Object obj = null;
        try {
            Query query = em.createNativeQuery(sql);
            if (args != null && args.size() > 0) {
                for (int i = 0; i < args.size(); i++) {
                    query.setParameter(i + 1, args.get(i));
                }
            }
            obj = query.getSingleResult();
        } catch (NoResultException ne){
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("EntityManager执行sql出错：" + e.getMessage());
        }
        return obj;
    }


    @Override
    @SuppressWarnings("unchecked")
    public List<Map<String, Object>> getListJdbc(String sql, List<Object> args) {
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        try {
            Query query = em.createNativeQuery(sql);
            query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
            if (args != null && args.size() > 0) {
                for (int i = 0; i < args.size(); i++) {
                    query.setParameter(i + 1, args.get(i));
                }
            }
            logger.info("sql:" + sql + " " + JSON.toJSONString(args));
            list = (List<Map<String, Object>>) query.getResultList();
        } catch (NoResultException ne){
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("EntityManager执行sql出错：" + e.getMessage());
        }
        return list;
    }

    @Override
    public int getListJdbcSize(String sql, List<Object> args) {
        int num = 0;
        try {
            sql = sql.toLowerCase();
            sql = "select count(1) num from (" + sql + ") t";
            Query query = em.createNativeQuery(sql);
            if (args != null && args.size() > 0) {
                for (int i = 0; i < args.size(); i++) {
                    query.setParameter(i + 1, args.get(i));
                }
            }
            logger.info("sql:" + sql + " " + JSON.toJSONString(args));
            num = Integer.parseInt(query.getSingleResult().toString());
        } catch (NoResultException ne){
            return 0;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("EntityManager执行sql出错：" + e.getMessage());
        }
        return num;
    }

    @Override
    public int updateJdbc(String sql, List<Object> arrList) {
        int num = 0;
        try {
            Query query = em.createNativeQuery(sql);
            if (arrList != null && arrList.size() > 0) {
                for (int i = 0; i < arrList.size(); i++) {
                    query.setParameter(i + 1, arrList.get(i));
                }
            }
            logger.info("sql:" + sql + " " + JSON.toJSONString(arrList));
            num = query.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("EntityManager执行sql出错：" + e.getMessage());
        }
        return num;
    }

    /**
     * 数据权限过滤
     * @param sql 原sql语句
     * @param arrList 原数据
     * @param unitAlias 单位表别名
     */
    @Override
    public void dataScopeFilter(Integer userId, StringBuilder sql, List<Object> arrList,String unitAlias,String selfAlias) {
        if (!StringUtil.isEmpty(sql.toString())) {
            List<Object> list = new ArrayList<>();
            StringBuilder data_scope = new StringBuilder();
            User user = UserUtils.get(userId+"");
            List<Role> roleList = user.getRoleList();
            Unit unit = user.getUnit();
            for (int i = 0; i < roleList.size(); i++) {
                Role role = roleList.get(i);
                if(i == 0){
                    data_scope.append(" and (");
                }else{
                    data_scope.append(" or ");
                }
                if (Role.DataScope.UNIT_ALL == role.getData_scope()) {
                    data_scope.setLength(0);
                    list.clear();
                    break;
                } else if (Role.DataScope.UNIT_AND_CHILD == role.getData_scope()) {
                    data_scope.append("(" + unitAlias + ".id  = ? or " + unitAlias + ".parent_ids like concat(?,'%') ) ");
                    list.add(unit.getId());
                    list.add(unit.getParent_ids() + unit.getId());
                } else if (Role.DataScope.UNIT_ONLY == role.getData_scope()) {
                    data_scope.append(unitAlias + ".id  = ? ");
                    list.add(unit.getId());
                } else if (Role.DataScope.ROLE_SET_UNIT == role.getData_scope()) {
                    data_scope.append("exist (select 1 from t_role_unit where role_id = ? and unit_id = " + unitAlias + ".id ) ");
                    list.add(role.getId());
                    list.add(unit.getId());
                } else if (Role.DataScope.SELF_ONLY == role.getData_scope()){
                    data_scope.append(selfAlias + ".creator = ? ");
                    list.add(userId);
                }
                if(i == roleList.size() - 1){
                    data_scope.append(") ");
                }
            }
            sql.append(data_scope);
            arrList.addAll(list);
        }
    }

}
